package com.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.api.core.config.WxConfig;
import com.api.core.constants.RedisConstants;
import com.api.core.util.ReqUtil;
import com.api.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service("redisService")
@Slf4j
public class RedisServiceImpl implements RedisService {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");

    private static final String scriptUnLock = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    private static final String scriptLock = "if redis.call('setNX',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end";


    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WxConfig appConfig;

    @Override
    public String leftPop(String key) {
        return stringRedisTemplate.opsForList().leftPop(key);
    }

    @Override
    public Long leftPush(String key, String value) {
        return stringRedisTemplate.opsForList().leftPush(key,value);
    }

    @Override
    public Long rightPush(String key, String value) {
        return  stringRedisTemplate.opsForList().rightPush(key,value);
    }

    @Override
    public boolean unLock(String key) {
        return 1 == myexecute(scriptUnLock,key.getBytes(),appConfig.redis_lock_value.getBytes());
    }

    @Override
    public boolean lock(String key,Long timeout) {
        return 1 == myexecute(scriptLock,key.getBytes(),appConfig.redis_lock_value.getBytes(),timeout.toString().getBytes());
    }

    @Override
    public String getMessage(byte[] body) {
        return (String) stringRedisTemplate.getValueSerializer().deserialize(body);
    }

    @Override
    public void sendMessage(String channel, String message) {
        stringRedisTemplate.convertAndSend(channel, message);
    }

    @Override
    public void setObject(String key, Object o, Long timeout) {
        stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(o));
        stringRedisTemplate.expire(key, timeout, TimeUnit.MINUTES);
    }

    @Override
    public boolean hasKey(String key) {
        return stringRedisTemplate.hasKey(key);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void expire(String key, Long timeout) {
        stringRedisTemplate.expire(key, timeout, TimeUnit.MINUTES);
    }

    @Override
    public void setString(String key, String str, Long timeout) {
        stringRedisTemplate.opsForValue().set(key, str);//向redis里存入数据和设置缓存时间
        stringRedisTemplate.expire(key, timeout, TimeUnit.MINUTES);//设置过期时间
    }

    @Override
    public void del(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public void hashPutObject(String key, String hashkey, Object o) {
        stringRedisTemplate.opsForHash().put(key, hashkey, JSON.toJSONString(o));
    }

    @Override
    public String hashGet(String key, String hashkey) {
        return (String) stringRedisTemplate.opsForHash().get(key, hashkey);
    }

    @Override
    public void hashDel(String key, String hashkey) {
        stringRedisTemplate.opsForHash().delete(key, hashkey);
    }

    @Override
    public boolean hashhasKey(String key, String hashkey) {
        return stringRedisTemplate.opsForHash().hasKey(key, hashkey);
    }

    @Override
    public Long getSingleId() {
        Long id = stringRedisTemplate.opsForHash().increment(RedisConstants.primary_key, RedisConstants.long_id, 1);
        if (id < 100000) {
            id = id + 100000;
            stringRedisTemplate.opsForHash().put(RedisConstants.primary_key, RedisConstants.long_id, "101000");
        }
        if (id > 998999)
            stringRedisTemplate.opsForHash().put(RedisConstants.primary_key, RedisConstants.long_id, "100000");
        String idStr = sdf.format(new Date());
        return Long.parseLong(idStr + id);
    }

    @Override
    public Integer getShortSingleId() {
        Long id = stringRedisTemplate.opsForHash().increment(RedisConstants.primary_key, RedisConstants.short_id, 1);
        if (id < 1000) {
            stringRedisTemplate.opsForHash().put(RedisConstants.primary_key, RedisConstants.short_id, String.valueOf(ReqUtil.getRandom(100, 999)));
            id = stringRedisTemplate.opsForHash().increment(RedisConstants.primary_key, RedisConstants.short_id, 1);
        }
        return id.intValue();
    }

    private Long myexecute(String script, byte[]... args){
        return  (Long) redisTemplate.execute((RedisConnection connection) -> connection.eval(
                script.getBytes(),
                ReturnType.INTEGER,
                1,
                args));

    }
}
